package com.slipper.system.flow.service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import com.slipper.constants.FlowConstants;
import com.slipper.system.flow.bo.FlowLineBO;
import com.slipper.system.flow.bo.FlowNodeBOs;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import com.slipper.system.flow.dao.FlowNodeDao;
import com.slipper.system.flow.bo.FlowNodeBO;
import com.slipper.core.transaction.ReadTransactional;
import com.slipper.core.transaction.WriteTransactional;
import com.slipper.util.Tool;

@Service
@ReadTransactional
public class FlowNodeService {
    @Resource
    private FlowNodeDao flowNodeDao;
    @Resource
    private FlowLineService flowLineService;

    public FlowNodeBO queryBy(String id){
        return flowNodeDao.queryBy(id);
    }

    public FlowNodeBO queryFirst(String flowId){
        List<FlowNodeBO> nodeList = flowNodeDao.queryFirst(flowId);
        return nodeList.isEmpty() ? null : nodeList.getFirst();
    }

    public PageInfo<FlowNodeBO> queryPage(FlowNodeBO bo){
        PageHelper.startPage(bo.getPageNumber(), bo.getPageSize());
        return new PageInfo<>(flowNodeDao.queryList(bo));
    }
    
    public List<FlowNodeBO> queryList(FlowNodeBO bo) {
        return flowNodeDao.queryList(bo);
    }
    
    @WriteTransactional
    public Integer save(FlowNodeBO bo){
        int result;
        if (bo.getId() != null && !"".equals(bo.getId())) {
            bo.setUpdateTime(System.currentTimeMillis());
            result = flowNodeDao.update(bo);
        } else {
            bo.setId(Tool.getUUID());
            bo.setUpdateTime(System.currentTimeMillis());
            bo.setCreateTime(System.currentTimeMillis());
            result = flowNodeDao.insert(bo);
        }
        
        return result;
    }
    
    @WriteTransactional
    public Integer delete(FlowNodeBO bo){
        return flowNodeDao.delete(bo);
    }

    public FlowNodeBO findFirstNode(String flowId) {
        FlowNodeBO qo = new FlowNodeBO();
        qo.setFlowId(flowId);
        List<FlowNodeBO> flowNodeList = this.flowNodeDao.queryList(qo);

        FlowLineBO seqQo = new FlowLineBO();
        seqQo.setFlowId(flowId);
        List<FlowLineBO> flowLineList = this.flowLineService.queryList(seqQo);

        // 开始节点
        List<FlowNodeBO> startList = flowNodeList.stream()
                .filter(flowNode -> FlowConstants.FlowNode.TYPE_START.equals(flowNode.getType()))
                .toList();
        if (startList.isEmpty()) {
            return null;
        }

        return this.findFirstManuallyNode(new HashSet<>(), startList.getFirst(), flowNodeList, flowLineList);
    }

    private FlowNodeBO findFirstManuallyNode(
            Set<String> flowNodeIdSet,
            FlowNodeBO flowNodeBO,
            List<FlowNodeBO> flowNodeList,
            List<FlowLineBO> flowLineList) {
        if (FlowConstants.FlowNode.TYPE_TASK.equals(flowNodeBO.getType())) {
            return flowNodeBO;
        }

        List<FlowLineBO> nextNodeList = flowLineList.stream()
                .filter(flowLine -> flowLine.getPreNodeId().equals(flowNodeBO.getFlowId()))
                .toList();
        for (FlowLineBO seqBO : nextNodeList) {
            FlowNodeBO flowNode = flowNodeList.stream()
                    .filter(node -> node.getId().equals(seqBO.getNextNodeId()))
                    .toList()
                    .getFirst();
            if (FlowConstants.FlowNode.TYPE_TASK.equals(flowNode.getType())) {
                return flowNode;
            }

            if (flowNodeIdSet.add(flowNode.getId())) {
                FlowNodeBO nextNode = this.findFirstManuallyNode(
                        flowNodeIdSet,
                        flowNode,
                        flowNodeList,
                        flowLineList);
                if (nextNode != null) {
                    return nextNode;
                }
            }
        }

        return null;
    }

    @WriteTransactional
    public int saveDealMan(FlowNodeBOs bos) {
        int result = 0;
        for (FlowNodeBO flowNode : bos.getList()) {
            flowNode.setUpdateTime(System.currentTimeMillis());
            result += flowNodeDao.updateDealMan(flowNode);
        }
        return result;
    }
}
